package Dispatcher;

import java.io.*;
import java.net.*;
import java.util.ArrayList;

/**
 * Group Dispatcher receives the floor calls and elevator destinations and
 * spawns various threads to send informations to different elevators
 * 
 * @author Varun Maryada, Sanat Dixit, Steve Tannahill
 * 
 */
public class GroupDispatcher {
	static final int MAX_ELEVATORS = 15;
	
	//receive these kind of messages
	static final int RECEIVED_INIT = 1;
	static final int RECEIVED_UPDATE = 4;

	private ServerSocket serverSocket;
	Socket tmpSocket;
	ArrayList<PrintWriter> elevators;
	ArrayList<ElevatorStatus> status;
	BufferedReader in;
	
	public GroupDispatcher() {
		elevators = new ArrayList<PrintWriter>(MAX_ELEVATORS);
		status = new ArrayList<ElevatorStatus>();
		serverSocket = null;
		try {
			serverSocket = new ServerSocket(5000);

		} catch (IOException e) {
			e.printStackTrace(System.err);
			System.exit(1);
		}
	}
	
	public ArrayList<PrintWriter> getElevators() {
		return elevators;
	}
	
	public BufferedReader getInputBufferReader() {
		return in;
	}
	
	public ArrayList<ElevatorStatus> getStatus() {
		return status;
	}
	
	public void handle(String msg) {
		byte[] bMsg = msg.getBytes();
		if (bMsg[0] == RECEIVED_INIT) {
			this.handleInit(bMsg, msg);
		}
		else if (bMsg[0] == RECEIVED_UPDATE) {
			this.handleUpdate(bMsg);
		}
		else {
			System.out.println("Received message from elevator: " + msg);
		}
	}

	public synchronized void handleInit(byte[] bMsg, String msg) {
		System.out.println("Found Elevator: " + (int) bMsg[1]
				+ "\n");
		// create PrintWriter for this elevator
		try {
			this.elevators.add(bMsg[1]-1, new PrintWriter(tmpSocket.getOutputStream(), true));
		} catch (IOException e) {
			System.out.println("IO Exception");
		}
		// send a start message to elevator
		elevators.get(bMsg[1]-1).println("Registered with Dispatcher");
	}

	public synchronized void handleUpdate(byte[] bMsg) {
		System.out.println("Received update from Elevator: " + (int) bMsg[1]
				+ "\n");
		this.status.add(bMsg[1]-1, new ElevatorStatus((int) bMsg[1],
				(int) bMsg[2], (int) bMsg[3], (int) bMsg[4], (int) bMsg[5]));
		
	}
	
	public void activateSocket() {
		try {
			tmpSocket = serverSocket.accept();
			in = new BufferedReader(new InputStreamReader(
					tmpSocket.getInputStream()));
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	public synchronized void processHallCall(int floorNumber, int direction) {
		SendHallCallRequestThread srt = new SendHallCallRequestThread(floorNumber,
				direction, this);
		srt.start();
	}

	public void processElevatorCall(int destination) {
		SendElevatorRequestThread srt = new SendElevatorRequestThread(
				destination, this);
		srt.start();
	}

	public String receiveMessage() {
		String msg;
		try {
			msg = in.readLine();
			return msg;
		} catch (SocketException e2) {
			System.out.println("Done");
			System.exit(0);
		} catch (IOException e) {
			e.printStackTrace(System.err);
			System.exit(1);
		}
		return "Failed";
	}

	public void sendMessage(int elevatorNum, String Msg) {

	}

	@Override
	public void finalize() {
		try {
			// close all sockets and PrintWriters
			serverSocket.close();
			in.close();
		} catch (IOException e) {
			System.out.println("IO Exception");
		}
	}

	public static void main(String args[]) {
		String msg;
		System.out.println("Started dispatcher");
		GroupDispatcher gd = new GroupDispatcher();
		// create and start an update thread if needed
		UpdateThread ut = new UpdateThread(gd);
		ut.start();
		gd.activateSocket();
		while (true) {
			msg = gd.receiveMessage();
			HandleReceivedMsgThread hrm = new HandleReceivedMsgThread(gd, msg);
			hrm.start();
		}
	}
}
